from typing import Dict, Any

from sqlalchemy import update, insert, select, func, and_, table
from sqlalchemy.ext.asyncio import AsyncSession

from common.JwtUtil import JwtUtil
from common.sqlalchemy_db import SqlalchemyX
from common.util import singleton
from modules.User import User

@singleton
class UserService:
    def __init__(self, session: AsyncSession = SqlalchemyX.AsyncSessionLocal()):
        self.session = session

    async def check_user_state(self, option: Dict[str, Any]) -> bool:
        result = await self.session.execute(select(User).filter_by(**option))
        user = result.scalars().first()
        if not user:
            return False
        return True

    async def check_user_existence(self, option: Dict[str, Any]) -> bool:
        count = await self._count(option)
        return count > 0

    async def user_register(self, register_user_mes: Dict[str, Any]) -> Dict[str, Any]:
        # 插入用户
        stmt = insert(User).values(**register_user_mes)
        await self.session.execute(stmt)
        await self.session.commit()

        # 返回用户基础信息
        return await self.get_user_basic_mes({"username": register_user_mes["username"]})

    async def check_user_password(self, username: str, password: str) -> bool:
        user = await self._find_by_username(username)
        if not user:
            return False
        return JwtUtil.verify_password(password, user.user_saltPassword)

    async def get_user_basic_mes(self, option: Dict[str, Any]) -> Dict[str, Any]:
        user = await self._find_one(option)
        if not user:
            raise ValueError("User not found")

        return {
            "user_id": user.user_id,
            "user_name": user.user_name,
            "user_avatar": user.user_avatar,
            "user_reg_time": user.user_reg_time,
            "user_lastLogin_time": user.user_lastLogin_time,
            "user_state": user.user_state,
            "user_socketId": user.user_socketId,
            "user_preferSetting_id": user.user_preferSetting_id
        }

    async def update_user(self, option: Dict[str, Any], update_content: Dict[str, Any]):
        where_clause = self._build_where_clause(option)
        stmt = update(User).where(where_clause).values(**update_content)
        await self.session.execute(stmt)
        await self.session.commit()

    # --------------------------
    # 内部辅助方法
    # --------------------------

    async def _find_one(self, option: Dict[str, Any]) -> User:
        async with SqlalchemyX.AsyncSessionLocal() as session:
            result = await session.execute(select(User).filter_by(**option))
            return result.scalars().first()

    async def _find_by_username(self, username: str) -> User:
        result = await self.session.execute(select(User).where(User.user_name == username))
        return result.scalars().first()

    async def _count(self, option: Dict[str, Any]) -> int:
        where_clause = self._build_where_clause(option)
        result = await self.session.execute(select(func.count()).where(where_clause))
        return result.scalar()

    def _build_where_clause(self, option: Dict[str, Any]):
        clauses = []
        for key, value in option.items():
            if hasattr(User, key):
                clauses.append(getattr(User, key) == value)
        return and_(*clauses)